#ifndef ROUTER_H
#define ROUTER_H

#include <functional>

#include "./Common.h"
#include "./Protocol.h"

namespace Reactor
{

class MOUDLE_API RouteNode
{
public:
	RouteNode(const std::string& _request, const std::string& _respones)
		:_request(_request), _respones(_respones)
	{

	}

	std::string respones() const
	{
		return _respones;
	}

	std::string request() const
	{
		return _request;
	}
	virtual ~RouteNode() = default;
	virtual bool needReturn()const = 0;
	virtual Poco::Buffer<char> toBodyBuffer(Protocol::ParseType,const std::shared_ptr<Protocol::DataBase>&) = 0;
	virtual std::shared_ptr<Protocol::DataBase> from(Protocol::ParseType _type, const Poco::Buffer<char>& _bodySource) = 0;
	virtual void handle(const Protocol::DataHead& dataHead, const Protocol::DataBase& data, std::shared_ptr<Protocol::DataBase>& pOut) = 0;
private:
	const std::string _request;
	const std::string _respones;
};

template<typename T> 
class RouteNodeHelper;

template<typename Cla, typename Head, typename Body>
class RouteNodeHelper<void(Cla::*)(const Head&, const Body&)> : public RouteNode
{
public:
	RouteNodeHelper(const std::string& _request, const std::string& _respones, Cla* _pCaller, void(Cla::* handle)(const Protocol::DataHead&, const Body&))
		:RouteNode(_request, _respones)
	{
		_call		= std::bind(handle, _pCaller, std::placeholders::_1, std::placeholders::_2);
		_from		= std::bind(&Body::from, std::placeholders::_1, std::placeholders::_2);
	}

	virtual Poco::Buffer<char> toBodyBuffer(Protocol::ParseType, const std::shared_ptr<Protocol::DataBase>&)override
	{
		return Poco::Buffer<char>(0);
	}

	virtual std::shared_ptr<Protocol::DataBase> from(Protocol::ParseType _type, const Poco::Buffer<char>& _bodySource) override
	{
		return _from(_type, _bodySource);
	}

	virtual bool needReturn()const
	{
		return false;
	}

	virtual void handle(const Protocol::DataHead& dataHead, const Protocol::DataBase& data , std::shared_ptr<Protocol::DataBase>& pOut) override
	{
		pOut = nullptr;
		_call(dynamic_cast<const Head&>(dataHead), dynamic_cast<const Body&>(data));
	}

private:
	std::function<void(const Head&, const Body&)>					_call;
	std::function<std::shared_ptr<Body>(Protocol::ParseType, const Poco::Buffer<char>&)>	_from;
};

template<typename Cla, typename Head, typename Body, typename Out>
class RouteNodeHelper<std::shared_ptr<Out>(Cla::*)(const Head&, const Body&)> : public RouteNode
{
public:
	RouteNodeHelper(const std::string& _request, const std::string& _respones, Cla* _pCaller, std::shared_ptr<Out>(Cla::* handle)(const Protocol::DataHead&, const Body&))
		:RouteNode(_request, _respones)
	{
		_call = std::bind(handle, _pCaller, std::placeholders::_1, std::placeholders::_2);
		_from = std::bind(&Body::from, std::placeholders::_1, std::placeholders::_2);
		_toBodyBuffer = std::bind(&Body::toBodyBuffer, std::placeholders::_1, std::placeholders::_2);
	}

	virtual Poco::Buffer<char> toBodyBuffer(Protocol::ParseType _type, const std::shared_ptr<Protocol::DataBase>& _basePtr)
	{
		return _toBodyBuffer(_type, dynamic_cast<const Out&>(*_basePtr));
	}

	virtual std::shared_ptr<Protocol::DataBase> from(Protocol::ParseType _type, const Poco::Buffer<char>& _bodySource) override
	{
		return _from(_type, _bodySource);
	}

	virtual bool needReturn()const
	{
		return true;
	}

	virtual void handle(const Protocol::DataHead& dataHead, const Protocol::DataBase& data,  std::shared_ptr<Protocol::DataBase>& pOut) override
	{
		pOut = _call(dynamic_cast<const Head&>(dataHead), dynamic_cast<const Body&>(data));
	}

private:
	std::function<Poco::Buffer<char>(Protocol::ParseType, const Out&)>											_toBodyBuffer;
	std::function<std::shared_ptr<Out>(const Head&, const Body&)>							_call;
	std::function<std::shared_ptr<Body>(Protocol::ParseType, const Poco::Buffer<char>&)>	_from;
};

}
#endif//ROUTER_H
